package com.demo.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.demo.schedule.medicine.MedicineRemindSchedule;
import com.demo.constant.Constant;
import com.demo.entity.*;
import com.demo.entity.Vo.MessageSocketVo;
import com.demo.enums.*;
import com.demo.jwt.JwtTokenUtil;
import com.demo.mapper.*;
import com.demo.response.Result;
import com.demo.schedule.regular.RegularMindSchedule;
import com.demo.service.IMessageService;
import com.demo.service.IVtePreventiveDoctorAdviceService;
import com.demo.service.IVtePreventiveService;
import com.demo.util.HeatUtil;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;

/**
 * vte诊断评估表 服务实现类
 *
 * @author zm
 * @since 2020-12
 */
@Service
@Slf4j
@Transactional
public class VtePreventiveServiceImpl extends ServiceImpl<VtePreventiveMapper, VtePreventive> implements IVtePreventiveService {
    @Resource
    VtePreventiveMapper vtePreventiveMapper;
    @Autowired
    IMessageService messageService;
    @Resource
    PatientMapper patientMapper;
    @Autowired
    IVtePreventiveDoctorAdviceService adviceService;
    @Resource
    VtePreventiveDoctorAdviceMapper adviceMapper;
    @Resource
    UserMapper userMapper;
    @Resource
    private MedicineMapper medicineMapper;
    @Resource
    private MessageRuleMapper messageRuleMapper;

    /**
     * 新增vte诊断评估
     *
     * @param vtePreventive 实体对象
     */
    @Override
    public Integer addVtePreventive(VtePreventive vtePreventive) throws Exception {
        PreventiveRiskRankEnum gard = getGrade(vtePreventive.getPreventiveRiskScore(), PreventiveTypeEnum.getByValue(vtePreventive.getPreventiveType()));
        vtePreventive.setPreventiveRiskRank(gard.getValue());
        save(vtePreventive);
        return vtePreventive.getVtePreventiveId();
    }

    /**
     * 更新vte诊断评估
     *
     * @param vtePreventive 实体对象
     * @return
     */
    @Override
    @Transactional
    public Result updateVtePreventive(VtePreventive vtePreventive) throws Exception {
        log.info("评估类型1Caprini(外科)2Padua(内科)---" + vtePreventive.getPreventiveType());
        if (vtePreventive.getUpdatedUserId() == null || vtePreventive.getVtePreventiveId() == null) {
            return Result.error(Constant.KEY_ID);
        }

        //签字后不能保存
        VtePreventive tive = vtePreventiveMapper.selectById(vtePreventive.getVtePreventiveId());
        if (tive.getSignUserId() != null) {
            throw new Exception("保存失败,已被" + userMapper.selectById(tive.getSignUserId()).getUserTrueName() + "签字");
        }

        //风险评估等级
        PreventiveRiskRankEnum riskRank = getGrade(vtePreventive.getPreventiveRiskScore(), PreventiveTypeEnum.getByValue(vtePreventive.getPreventiveType()));
        vtePreventive.setPreventiveRiskRank(riskRank.getValue());
        updateById(vtePreventive);
        return Result.success();
    }

    /**
     * 删除vte诊断评估
     *
     * @param vtePreventiveId VTE诊断评估ID
     * @param deletedUserId   删除人ID
     * @return
     */
    @Override
    public Result deleteVtePreventive(Integer vtePreventiveId, Integer deletedUserId) {
        VtePreventive preventive = new VtePreventive();
        preventive.setDeletedTime(new Date());
        preventive.setDeletedUserId(deletedUserId);
        preventive.setVtePreventiveId(vtePreventiveId);
        boolean flag = updateById(preventive);
        if (flag == false) {
            return Result.error(Constant.DB_ERROR);
        }
        return Result.success();
    }

    /**
     * vte诊断评估列表
     *
     * @param pageNumber      页码
     * @param pageSize        大小
     * @param vtePreventiveId VTE诊断评估ID
     * @param patientId       病患ID
     * @return
     */
    @Override
    public Result vtePreventiveList(Integer pageNumber, Integer pageSize, Integer vtePreventiveId, Integer patientId) {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
        Integer uid = JwtTokenUtil.decodeTokenUserId(request.getHeader("token"));
        Page<VtePreventive> page = new Page<>(pageNumber.intValue(), pageSize.intValue());
        QueryWrapper<VtePreventive> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq((vtePreventiveId != null), "vte_preventive_id", vtePreventiveId);
        queryWrapper.eq((patientId != null), "patient_id", patientId);
        queryWrapper.isNull("deleted_user_id");
        queryWrapper.and(wrapper -> wrapper.eq("created_user_id", uid).or(wq -> wq.ne("created_user_id", uid).isNotNull("risk_confirm_time")));
        queryWrapper.orderByDesc("vte_preventive_id");

        IPage<VtePreventive> iPage = vtePreventiveMapper.selectPage(page, queryWrapper);
        ArrayList<Map<String, Object>> vtePreventiveList = new ArrayList();
        for (VtePreventive item : iPage.getRecords()) {
            Map<String, Object> newItem = BeanUtil.beanToMap(item);
            newItem.put("riskConfirmUserId", item.getRiskConfirmUserId());
            if (item.getRiskConfirmUserId() != null) {
                newItem.put("riskConfirmUserName", (userMapper.selectById(item.getRiskConfirmUserId())).getUserTrueName());
            } else {
                newItem.put("riskConfirmUserName", "");
            }
            if (item.getSignUserId() != null) {
                newItem.put("signUserName", (userMapper.selectById(item.getSignUserId())).getUserTrueName());
            } else {
                newItem.put("signUserName", "");
            }
            vtePreventiveList.add(newItem);
        }
        PageInfo<VtePreventive> pageInfo = new PageInfo(vtePreventiveList);
        pageInfo.setPages((int) iPage.getPages());
        pageInfo.setTotal(iPage.getTotal());
        if (pageNumber.equals(Long.valueOf(iPage.getPages()))) {
            pageInfo.setIsLastPage(false);
        } else {
            pageInfo.setIsLastPage(true);
        }
        return Result.success(pageInfo);
    }

    /**
     * 是否存在冲突医嘱---药物
     *
     * @param patientId
     */
    @Transactional
    public void getConflictDoctor(List<VtePreventiveMedicine> preventiveMedicines, Integer patientId) throws Exception {
        log.info("判断是否存在重复医嘱.......");
        for (VtePreventiveMedicine preventiveMedicine : preventiveMedicines) {
            List<Integer> list = adviceMapper.selectRepeatDoctor(patientId, preventiveMedicine.getMedicineId());
            if (list.size() != 0) {
                throw new Exception(preventiveMedicine.getName() + ",医嘱冲突");
            }
        }
    }

    /**
     * 是否存在冲突医嘱--物理
     */
    public void getConflictDoctorPhysical(Integer patientId, Integer adviseType) throws Exception {
        QueryWrapper<VtePreventiveDoctorAdvice> vtePreventiveDoctorAdviceQueryWrapper = new QueryWrapper();
        vtePreventiveDoctorAdviceQueryWrapper.eq("advise_type", adviseType);
        vtePreventiveDoctorAdviceQueryWrapper.eq("patient_id", patientId);
        vtePreventiveDoctorAdviceQueryWrapper.eq("status", PreventiveDoctorAdviceStatusEnum.UN_STOP.getValue());
        vtePreventiveDoctorAdviceQueryWrapper.isNull("deleted_time");
        vtePreventiveDoctorAdviceQueryWrapper.last("limit 1");
        VtePreventiveDoctorAdvice vtePreventiveDoctorAdvice = adviceMapper.selectOne(vtePreventiveDoctorAdviceQueryWrapper);
        if (vtePreventiveDoctorAdvice != null) {
            if (adviseType.intValue() == VtePreventiveDoctorAdviceTypeEnum.WU_LI_IPC.getValue()) {
                throw new Exception("IPC医嘱冲突");
            }
            if (adviseType.intValue() == VtePreventiveDoctorAdviceTypeEnum.WU_LI_GCS.getValue()) {
                throw new Exception("抗血栓梯度压力带医嘱冲突");
            }
        }
    }

    /**
     * 通过计算分数，获取等级
     *
     * @param fraction   评估得分
     * @param department 诊断类别1Caprini(外科)2Padua(内科)
     * @return
     */
    public PreventiveRiskRankEnum getGrade(Integer fraction, PreventiveTypeEnum department) {
        if (department == PreventiveTypeEnum.CAPRINI) {
            if (fraction == 0) {
                return PreventiveRiskRankEnum.CAPRINI_JI_DI;
            }
            if (fraction == 1 || fraction == 2) {
                return PreventiveRiskRankEnum.CAPRINI_DI_WEI;
            }
            if (fraction == 3 || fraction == 4) {
                return PreventiveRiskRankEnum.CAPRINI_ZHONG_WEI;
            }
            if (fraction > 4) {
                return PreventiveRiskRankEnum.CAPRINI_GAO_WEI;
            }
        }
        if (department == PreventiveTypeEnum.PADUA) {
            if (fraction < 4) {
                return PreventiveRiskRankEnum.PADUA_DI_WEI;
            } else if (fraction >= 4) {
                return PreventiveRiskRankEnum.PADUA_GAO_WEI;
            }
        }
        return null;
    }

    /**
     * 护士签字---复核评估消息,需要护士评估后签字再发送消息
     *
     * @param preventiveType      评估类型（1.外科  2.内科）
     * @param patientId           患者ID
     * @param vtePreventiveId     VTE评估主键ID
     * @param riskConfirmUserId   签字用户ID
     * @param preventiveRiskRank  风险评估层级
     * @param preventiveRiskScore 风险评估得分
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED, rollbackFor = {Exception.class, Error.class})
    public void nurseSignature(Integer preventiveType, Integer patientId, Integer vtePreventiveId, Integer riskConfirmUserId, Integer preventiveRiskRank, Integer preventiveRiskScore, String userPass) throws Exception {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
        Integer uid = JwtTokenUtil.decodeTokenUserId(request.getHeader("token"));
        User user = userMapper.getUserByPass(uid, HeatUtil.md5(userPass));
        if (user == null) {
            throw new Exception("密码错误");
        }
        VtePreventive inVtePreventive = vtePreventiveMapper.selectById(vtePreventiveId);
        if (inVtePreventive.getRiskConfirmUserId() != null) {
            throw new Exception("签字失败,已被" + (userMapper.selectById(inVtePreventive.getRiskConfirmUserId())).getUserTrueName() + "签字");
        }
        PreventiveTypeEnum preventiveTypeEnum = PreventiveTypeEnum.getByValue(preventiveType);

        PreventiveRiskRankEnum riskRank = getGrade(preventiveRiskScore, preventiveTypeEnum);
        VtePreventive vtePreventive = new VtePreventive();
        vtePreventive.setVtePreventiveId(vtePreventiveId);
        vtePreventive.setRiskConfirmUserId(riskConfirmUserId);
        vtePreventive.setRiskConfirmTime(new Date());
        vtePreventiveMapper.updateById(vtePreventive);
        Patient patient = patientMapper.selectById(patientId);
        Map<String, Object> msgContent = new HashMap<>();
        msgContent.put("bed_id", patient.getBedId());
        msgContent.put("bed_name", patient.getBedName());
        msgContent.put("patient_name", patient.getPatientName());
        msgContent.put("grade_name", riskRank.getDesc());
        msgContent.put("grade", riskRank.getValue());
        msgContent.put("dept_name", patient.getDeptName());
        msgContent.put("dept_sn", patient.getDeptSn());
        msgContent.put("message_text", String.format("初始评估为<span style=\"color:red\">%s</span>, 需要你进行进一步复核和进行禁忌评估", riskRank.getDesc()));
        if (preventiveTypeEnum == PreventiveTypeEnum.CAPRINI) { // 外科
            messageService.sendMessageNotification(MessageRemindEnum.UN_KNOWN_REMIND, patient, MessageSourceEnum.OTHER, msgContent, uid);
        } else if (preventiveTypeEnum == PreventiveTypeEnum.PADUA) { // 内科
            if (riskRank == PreventiveRiskRankEnum.PADUA_GAO_WEI) {
                messageService.sendMessageNotification(MessageRemindEnum.UN_KNOWN_REMIND, patient, MessageSourceEnum.OTHER, msgContent, uid);
            }
        }
    }

    /**
     * 医生签字
     *
     * @param patientId
     * @param vtePreventiveId VTE评估主键ID
     * @param signUserId      签字人ID
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = {Exception.class, Error.class})
    public void doctorsSignature(Integer patientId, Integer vtePreventiveId, Integer signUserId, String userPass) throws Exception {
        //当前登录用户可能是医生，护士等。
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
        Integer uid = JwtTokenUtil.decodeTokenUserId(request.getHeader("token"));
        User user = userMapper.getUserByPass(uid, HeatUtil.md5(userPass));
        if (user == null) {
            throw new Exception("密码错误");
        }

        //A与B医生同时签字
        VtePreventive tive = vtePreventiveMapper.selectById(vtePreventiveId);
        if (tive.getSignUserId() != null) {
            throw new Exception("签字失败,已被" + userMapper.selectById(tive.getSignUserId()).getUserTrueName() + "签字");
        }
        //发送消息
        messageSendVte(tive, uid);
    }

    /**
     * 医生签字后发送消息
     *
     * @param vtePreventive
     */
    public void messageSendVte(VtePreventive vtePreventive, Integer userId) throws Exception {
        Patient patient = patientMapper.getDetailsById(vtePreventive.getPatientId());
        if (vtePreventive.getDrugPrevention() != null && vtePreventive.getDrugPrevention().equals(1)) {//开了药物预防
            // 药物预防处理
            JSONObject preventiveTabooAdvise = JSON.parseObject(vtePreventive.getPreventiveTabooAdvise());
            if (preventiveTabooAdvise.containsKey("药物预防")) {
                List<VtePreventiveMedicine> preventiveMedicines = JSON.parseArray(JSON.toJSONString(preventiveTabooAdvise.get("药物预防")), VtePreventiveMedicine.class);
                // 判断当前新签字的医嘱里面有没有和前面医嘱里面药物有冲突的情况
                getConflictDoctor(preventiveMedicines, patient.getPatientId());
                for (VtePreventiveMedicine preventiveMedicine : preventiveMedicines) {
                    VtePreventiveDoctorAdvice advice = new VtePreventiveDoctorAdvice(preventiveMedicine, vtePreventive, userId);
                    // 药品&规则
                    int insert = adviceMapper.insert(advice);
                    if (insert > 0) {
                        VtePreventiveDoctorAdvice vtePreventiveDoctorAdvice = adviceMapper.selectById(advice.getDoctorAdviceId());
                        addMedicineRemindThread(vtePreventiveDoctorAdvice);
                    }
                }
            }
        }
        if (vtePreventive.getPhysicalPrevention() != null && vtePreventive.getPhysicalPrevention().equals(1)) {//开了物理预防
            // 物理预防处理
            JSONObject preventiveTabooAdvise = JSON.parseObject(vtePreventive.getPreventiveTabooAdvise());
            if (preventiveTabooAdvise.containsKey("物理预防")) {
                VtePreventivePhysical physical = JSON.parseObject(JSON.toJSONString(preventiveTabooAdvise.get("物理预防")), VtePreventivePhysical.class);
                if (physical.getIPC() != null && physical.getIPC()) {
                    getConflictDoctorPhysical(patient.getPatientId(), VtePreventiveDoctorAdviceTypeEnum.WU_LI_IPC.getValue());
                    VtePreventiveDoctorAdvice advice = new VtePreventiveDoctorAdvice(vtePreventive, preventiveTabooAdvise.toString(), VtePreventiveDoctorAdviceTypeEnum.WU_LI_IPC);
                    adviceMapper.insert(advice);
                }
                if (physical.getGCS() != null && physical.getGCS()) {
                    getConflictDoctorPhysical(patient.getPatientId(), VtePreventiveDoctorAdviceTypeEnum.WU_LI_GCS.getValue());
                    VtePreventiveDoctorAdvice advice = new VtePreventiveDoctorAdvice(vtePreventive, preventiveTabooAdvise.toString(), VtePreventiveDoctorAdviceTypeEnum.WU_LI_GCS);
                    adviceMapper.insert(advice);
                }
            }
        }

        // 更新诊断评估表数据
        VtePreventive vteUpdate = new VtePreventive();
        vteUpdate.setVtePreventiveId(vtePreventive.getVtePreventiveId());
        log.info("传过来数据{}", vtePreventive);
        if (vtePreventive.getRiskConfirmTime() == null) {
            vteUpdate.setRiskConfirmTime(new Date());
            vteUpdate.setRiskConfirmUserId(userId);
        }
        vteUpdate.setSignTime(new Date());
        vteUpdate.setSignUserId(userId);
        int result = vtePreventiveMapper.updateById(vteUpdate);
        if (vtePreventive.getDrugPrevention() != null || vtePreventive.getPhysicalPrevention() != null) {
            // 组装医嘱消息
            log.info("发送医嘱消息");
            String gradeName = PreventiveRiskRankEnum.getByValue(vtePreventive.getPreventiveRiskRank()).getDesc();
            Map<String, Object> msgContent = new HashMap<>();
            msgContent.put("bed_id", patient.getBedId());
            msgContent.put("bed_name", patient.getBedName());
            msgContent.put("patient_name", patient.getPatientName());
            msgContent.put("grade_name", gradeName);
            msgContent.put("grade", vtePreventive.getPreventiveRiskRank());
            msgContent.put("dept_name", patient.getDeptName());
            msgContent.put("dept_sn", patient.getDeptSn());
            msgContent.put("message_text", "有预防<span style=\"color:red\">措施/医嘱</span>需要执行，请前往处理");
            messageService.sendMessageNotification(MessageRemindEnum.CHU_ZHI_REMIND, patient, MessageSourceEnum.OTHER, msgContent, userId);
        }

        if (result == 1 && vtePreventive.getDiagnoseOpportunity() == PreventiveDiagnoseOpportunityEnum.DING_QI.getValue()) {
            vtePreventive = vtePreventiveMapper.selectById(vteUpdate.getVtePreventiveId());
            if (vtePreventive != null) {
                //添加定时消息提醒
                RegularMindSchedule.addVteTask(vtePreventive);
            }
        }
    }

    /**
     * 添加药物提醒
     * @param vtePreventiveDoctorAdvice
     */
    public void addMedicineRemindThread(VtePreventiveDoctorAdvice vtePreventiveDoctorAdvice) {
        Medicine medicine = medicineMapper.selectById(vtePreventiveDoctorAdvice.getDrugId());
        if (medicine == null) {
            return;
        }
        // 只处理添加提醒一次的规则
        List<MessageRule> messageRules = messageRuleMapper.queryListInEffective(vtePreventiveDoctorAdvice.getDrugId());
        for (MessageRule messageRule : messageRules) {
            MedicineRemindSchedule.addMedicineRemindTask(medicine, messageRule, vtePreventiveDoctorAdvice);
        }
    }

    @Override
    public Result getVteDeptSnRanking(String orderType, Integer topNumber) throws Exception {
        return Result.success(vtePreventiveMapper.getVteDeptSnRanking(orderType, topNumber));
    }

    @Override
    public Result getVteBleedDeptSnRanking(String orderType, Integer topNumber) throws Exception {
        return Result.success(vtePreventiveMapper.getVteBleedDeptSnRanking(orderType, topNumber));
    }

    @Override
    public Result getVtePreventiveInterval() throws Exception {
        Integer[] middleHigh = {3};
        Integer[] lowRank = {4};
        Integer[] highRank = {2};
        List<MessageSocketVo> messageList = vtePreventiveMapper.getVtePreventiveIntervalDay(lowRank, 7, middleHigh, 4, highRank, 1);
        try {
            for (MessageSocketVo messageSocketVo : messageList) {
                log.info("当前处理定时消息{}", messageSocketVo);
                QueryWrapper<Message> messageQueryWrapper = new QueryWrapper();
                messageQueryWrapper.select(new String[]{"created_time"});
                messageQueryWrapper.eq("message_source_sn", messageSocketVo.getMessageSourceSn());
                messageQueryWrapper.eq("message_source", MessageSourceEnum.OTHER.getValue());
                messageQueryWrapper.eq("message_status", MessageStatusEnum.UN_HANDLE.getValue());
                messageQueryWrapper.eq("message_type", MessageTypeEnum.PING_GU_REMIND.getValue());
                messageQueryWrapper.orderByDesc("message_id");
                messageQueryWrapper.last("limit 1");
                Message messageIn = messageService.getOne(messageQueryWrapper);
                DateTime dateTime = DateUtil.parse(DateUtil.now(), "yyyy-MM-dd HH:mm:ss");
                Patient patient = patientMapper.selectById(messageSocketVo.getPrientId());
                Map<String, Object> msgContent = new HashMap<>();
                msgContent.put("bed_id", patient.getBedId());
                msgContent.put("bed_name", patient.getBedName());
                msgContent.put("patient_name", patient.getPatientName());
                msgContent.put("grade", messageSocketVo.getPreventiveRiskRank());
                msgContent.put("grade_name", PreventiveRiskRankEnum.getByValue(messageSocketVo.getPreventiveRiskRank()).getDesc());
                msgContent.put("dept_name", patient.getDeptName());
                msgContent.put("dept_sn", patient.getDeptSn());
                if (messageIn != null) {
                    log.info("上次发送消息时间：" + messageIn.getCreatedTime() + "当前时间：" + dateTime + "相差时间{}", Long.valueOf(DateUtil.between(dateTime, messageIn.getCreatedTime(), DateUnit.DAY)));
                    if (DateUtil.between(dateTime, messageIn.getCreatedTime(), DateUnit.DAY) > 1L) {
                        msgContent.put("message_text", "病人上次评估结果为<span style=\"color:red\">" + PreventiveRiskRankEnum.getByValue(messageSocketVo.getPreventiveRiskRank()).getDesc() + "</span>,请进行动态评估");
                        messageService.sendMessageNotification(MessageRemindEnum.PING_GU_REMIND, patient, MessageSourceEnum.OTHER, msgContent, 0);
                    }
                    continue;
                }
                msgContent.put("message_text", "病人上次评估结果为<span style=\"color:red\">" + PreventiveRiskRankEnum.getByValue(messageSocketVo.getPreventiveRiskRank()).getDesc() + "</span>,请进行动态评估");
                messageService.sendMessageNotification(MessageRemindEnum.PING_GU_REMIND, patient, MessageSourceEnum.OTHER, msgContent, 0);
            }
        } catch (Exception e) {
            log.error("定时消息错误{}", e);
        }
        return Result.success(messageList);
    }
}
